﻿using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

namespace RabbitMQDemo.Consumer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Start consumers");

            var connFactory = new ConnectionFactory
            {
                HostName = "106.53.127.56",
                Port = 5672,
                UserName = "rabbitmqdemo",
                Password = "rabbitmqdemo@test",
                VirtualHost = "rabbitmqdemo",

            };
            using (var conn = connFactory.CreateConnection())
            {
                using (var channel = conn.CreateModel())
                {
                    var queueName = "messageheaderretrycount_queue";
                    channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
                    channel.BasicQos(0, 5, false);

                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var message = ea.Body;
                        Console.WriteLine("接收到信息为:" + Encoding.UTF8.GetString(message.ToArray()));

                        if (Encoding.UTF8.GetString(message.ToArray()).Contains("5"))
                        {
                            var maxRetryCount = 3;

                            Console.WriteLine($"拒收 {DateTime.Now}");

                            //初次消费
                            if (ea.BasicProperties.Headers == null)
                            {
                                //原消息设置为不重入队列
                                ((EventingBasicConsumer)model).Model.BasicReject(ea.DeliveryTag, requeue: false);

                                //发送新消息到队列中
                                RetryPublishMessage(channel, queueName, message.ToArray(), 1);
                                return;
                            }

                            //获取重试次数
                            var retryCount = ParseRetryCount(ea);
                            if (retryCount < maxRetryCount)
                            {
                                //原消息设置为不重入队列
                                ((EventingBasicConsumer)model).Model.BasicReject(ea.DeliveryTag, requeue: false);

                                //发送新消息到队列中
                                RetryPublishMessage(channel, queueName, message.ToArray(), retryCount + 1);
                                return;
                            }

                            //到达最大次数，不再重试消息
                            ((EventingBasicConsumer)model).Model.BasicReject(ea.DeliveryTag, requeue: false);
                            return;
                        }

                        ((EventingBasicConsumer)model).Model.BasicAck(ea.DeliveryTag, multiple: false);
                    };

                    channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
                    Console.ReadKey();

                    static void RetryPublishMessage(IModel channel, string queueName, byte[] body, int retryCount)
                    {
                        var basicProperties = channel.CreateBasicProperties();
                        basicProperties.Headers = new Dictionary<string, object>();
                        basicProperties.Headers.Add("retryCount", retryCount);
                        channel.BasicPublish(exchange: "", routingKey: queueName, basicProperties: basicProperties, body: body);
                    }

                    static int ParseRetryCount(BasicDeliverEventArgs ea)
                    {
                        var existRetryRecord = ea.BasicProperties.Headers.TryGetValue("retryCount", out object retryCount);
                        if (!existRetryRecord)
                        {
                            throw new Exception("没有设置重试次数");
                        }

                        return (int)retryCount;
                    }
                }
            }
        }
    }
}